package com.yqb.study.modular.service.impl;

import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.plugins.Page;
import com.yqb.study.common.exception.GlobalException;
import com.yqb.study.common.lock.RedisLock;
import com.yqb.study.common.session.IRedisSession;
import com.yqb.study.constant.CodeMsgEnum;
import com.yqb.study.constant.key.redis.RedisLockKey;
import com.yqb.study.modular.dao.mysql.SecKillDao;
import com.yqb.study.modular.dto.Exposer;
import com.yqb.study.modular.persistence.dao.SeckillMapper;
import com.yqb.study.modular.persistence.dao.SuccessKilledMapper;
import com.yqb.study.modular.persistence.model.Seckill;
import com.yqb.study.modular.persistence.model.SuccessKilled;
import com.yqb.study.modular.service.ISecKillService;

import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class SecKillServiceImpl implements ISecKillService {

	@Autowired
	private SecKillDao secKillDao;	
	@Autowired
	private SeckillMapper secKillMapper;
	@Autowired
	private SuccessKilledMapper successKilledMapper;	
	@Autowired
	private RedisLock redisLock;

	@Override
	public List<Seckill> getSeckillList(Page<Seckill> page, Map<String, Object> searchCond) {

		List<Seckill> secKillList = secKillDao.getPageSeckillInfo(page, searchCond);
		return secKillList;
	}

	@Override
	public Exposer exportSeckillUrl(long seckillId) {
		// TODO Auto-generated method stub
		return null;
	}
	
	/**
	 * TPS : 16
     * 使用注解控制事务的优点:
     * 1.开发团队达成一致约定,明确标注事务方法的编程风格.
     * 2.保证事务方法的执行时间尽可能短,不要穿插其他网络操作RPC/HTTP请求/操作缓存,可以将前面这些操作剥离到事务方法外部,尽量保证事务方法运行够快够干净.
     * 3.不是所有的方法都需要事务.如一些查询的service.只有一条修改操作的service.
     */
	@Override
	@Transactional
	public CodeMsgEnum secKillProduct1(IRedisSession redisSession, Long secKillId) {

		// String lockKey = RedisLockKey.lock.getPrefix() + this.getClass().getSimpleName();
		String lockKey = RedisLockKey.lock.getPrefix() + Thread.currentThread().getStackTrace()[2].getMethodName();
		String lockValue = String.valueOf(System.currentTimeMillis() + RedisLockKey.lock.expireSeconds() * 1000);		
		
		try {
			if (!redisLock.lock(lockKey, lockValue)) {
				throw new GlobalException(CodeMsgEnum.REQ_TOO_QUICK);
			}
			
			// 检查库存
			Seckill seckill = new Seckill();
			seckill.setSeckillId(secKillId);
			seckill = secKillMapper.selectOne(seckill);
			int canBuyNum = seckill.getNumber();
			if (canBuyNum == 0) {
				throw new GlobalException(CodeMsgEnum.GOODS_IS_OVER);
			}
			
			// 检查用户是否购买过
			SuccessKilled successKilledWrapper = new SuccessKilled();
			successKilledWrapper.setSeckillId(secKillId);
			successKilledWrapper.setUserPhone(Long.valueOf(redisSession.getSessionRedis().getUser().getPhone()));
			if (successKilledMapper.selectOne(successKilledWrapper) != null) {
				throw new GlobalException(CodeMsgEnum.BUY_SAME_GOOD);
			}
			
			// 购买一件
			seckill.setNumber(canBuyNum - 1);

//			try {
//				Thread.sleep(100);
//			} catch (InterruptedException e) {
//				// TODO Auto-generated catch block
//				e.printStackTrace();
//			}
			
			seckill.updateById();
			// 加入订单表
			SuccessKilled successKilled = new SuccessKilled();
			successKilled.setSeckillId(secKillId);
			successKilled.setUserPhone(Long.valueOf(redisSession.getSessionRedis().getUser().getPhone()));		
			successKilledMapper.insert(successKilled);		
			
			// ------确定库存更新了-------
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}		
			// ------确定库存更新了-------
			
		} finally {
			/**
			 * 一定要注意解锁
			 */
			redisLock.unlock(lockKey, lockValue);
		}

		return CodeMsgEnum.SEC_KILL_SUCCESS;
	}
}
